﻿-- Author      : Kurapica
-- Create Date : 9/6/2008
--[[
    There are two widget types in this file.
    The user can only create TabGroup, the TabButton can only be created by TabGroup.
--]]
-- TabGroup
do
	-- Check Version
	local version = 1
	if not IGAS:RegisterFile("IGAS.GUI.Widget.TabGroup", version) then
		return
	end

    local getmetatable = getmetatable
    local pairs = pairs
    local ipairs = ipairs
    local type = type
    local error = error
    local CreateFrame = IGAS.GUI.CreateFrame
    
	local _GUI = IGAS.GUI
	local _Widget = IGAS.GUI.Widget
    local _BaseFunc = IGAS.GUI.Base.Func
	local _Enum = IGAS.GUI.Base.Enum
	local _PropertyType = IGAS.GUI.Base.PropertyType
	
    -- TabAlignment
    local TABALIGN_TOP = "Top"
    local TABALIGN_BOTTOM = "Bottom"
    local TABALIGN_LEFT = "Left"
    local TABALIGN_RIGHT = "Right"
    
    local BUTTON_HEIGHT = 32
    --[[
    -- Define TabAlignment
    _Enum["TabAlignment"] = {
        TABALIGN_TOP,
        TABALIGN_BOTTOM,
        --TABALIGN_LEFT,
        --TABALIGN_RIGHT,
    }
    
    _PropertyType["TabAlignment"] = {
        ["Type"] = "enum",
		["EnumType"] = _Enum.TabAlignment,
    }--]]
    
    ------------------------------------------------------
	---------------------- TabButton ---------------------
	------------------------------------------------------
    local TabButton
    
    do
        local _WidgetName = "TabButton"
        local _Base = "Button"
        
        -- Scripts
        local _FrameBackdrop = {
            bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
            edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
            tile = true, tileSize = 16, edgeSize = 16,
            insets = { left = 3, right = 3, top = 3, bottom = 3 }
        }
    
        local function OnClick(self)
            self:Select()
        end
        
        local function UpdateTabLook(self)
            if self.__Selected then
                self:GetChild("Left"):SetAlpha(1)
                self:GetChild("Right"):SetAlpha(1)
                self:GetChild("Middle"):SetAlpha(1)
                self:GetChild("Text"):SetTextColor(1,1,1)
                self:GetHighlightTexture():Hide()
                self.__Container:Show()
            else
                self:GetChild("Left"):SetAlpha(0.5)
                self:GetChild("Right"):SetAlpha(0.5)
                self:GetChild("Middle"):SetAlpha(0.5)
                self:GetChild("Text"):SetTextColor(1,0.82,0)
                self:GetHighlightTexture():Show()
                self.__Container:Hide()
            end
            
            if self.__Disabled then
                self:GetChild("Text"):SetTextColor(0.5,0.5,0.5)
                self:GetHighlightTexture():Hide()
            end
        end
		
        -- ScriptType
        local _ScriptType = {
            ["OnTabSelect"] = true,
        }
		        
        -- FuncProxy
        local _FuncProxy = {
            ["SetText"] = function(self, text)
                self:GetChild("Text").Text = text
                self.Width = self:GetChild("Text").Width + 20
            end,
            
            ["GetText"] = function(self)
                return self:GetChild("Text").Text
            end,
            
            ["Select"] = function(self)
                if self.__Disabled or self.__Selected then
                    return
                end
                
                self.__Selected = true
                UpdateTabLook(self)
                
                -- Others
                local parent = self.Parent
                
                for i = 1, parent.__TabNum do
                    if i ~= self.__TabIndex and parent:GetChild("TabButton"..i) then
                        parent:GetChild("TabButton"..i).Selected = false
                    end
                end
                
                self:Fire("OnTabSelect")
            end,
            
            ["IsSelected"] = function(self)
                return self.__Selected
            end,
            
            ["Disable"] = function(self)
                local parent = self.Parent
                local selTab
                
				self.__Disabled = true
                
                if self.__Selected then
                    for i = 1, parent.__TabNum do
                        if i ~= self.__TabIndex then
                            selTab = parent:GetChild("TabButton"..i)
                            
                            if selTab and selTab:IsEnabled() then
                                selTab:Select()
                                break
                            end
                        end
                    end
                end
				
                UpdateTabLook(self)
            end,
            
            ["Enable"] = function(self)
                self.__Disabled = false
                UpdateTabLook(self)
            end,
            
            ["IsEnabled"] = function(self)
                return (not self.__Disabled)
            end,

            ["GetContainer"] = function(self)
                return self.__Container
            end,
            
            -- Dispose, release resource
            ["Dispose"] = function(self)
                local parent = self.Parent
                local selTab
                
                self:Disable()
                
                -- DisSelect
                --[[if parent.__TabNum and parent.__TabNum > 0 and self.__Selected then
                    for i = 1, parent.__TabNum do
                        if i ~= self.__TabIndex then
                            selTab = parent:GetChild("TabButton"..i)
                            
                            if selTab and selTab:IsEnabled() then
                                selTab:Select()
                                break
                            end
                        end
                    end
                end--]]
                
                -- Parent Map
                selTab = parent:GetChild("TabButton"..(self.__TabIndex+1))
                
                if selTab then
                    if self.__TabIndex == 1 then
						selTab:SetPoint("TOPLEFT", parent, "TOPLEFT", 0, 0)
                    else
                        selTab:SetPoint("TOPLEFT", parent:GetChild("TabButton"..(self.__TabIndex-1)), "TOPRIGHT", 0, 0)
                    end
                end
                
                self:Hide()
                self.__Container:Dispose()
                
                parent:RemoveChild(self)
                
                if parent.__TabNum > self.__TabIndex then
                    for i = self.__TabIndex + 1, parent.__TabNum do
                        parent:GetChild("TabButton"..i).__TabIndex = i-1
	                    parent:GetChild("TabButton"..i).Name = "TabButton"..(i - 1)
	                end
                end
                
                parent.__TabNum = parent.__TabNum - 1
                
                -- Call super's dispose
				self:CallMethod(_Widget[_Base], "Dispose")
            end,
        }
        
        -- Property
        local _Property = {
            -- Enabled
            ["Enabled"] = {
                ["Set"] = function(self, flag)
                    if flag then
                        self:Enable()
                    else
                        self:Disable()
                    end
                end,
                
                ["Get"] = function(self)
                    return (self:IsEnabled() and true) or false
                end,
                
                ["Type"] = _PropertyType.Boolean,
            },
            -- Selected
            ["Selected"] = {
                ["Set"] = function(self, flag)
                    if flag then
                        self:Select()
                    else
                        self.__Selected = false
                        UpdateTabLook(self)
                    end
                end,
                
                ["Get"] = function(self)
                    return (self:IsSelected() and true) or false
                end,
                
                ["Type"] = _PropertyType.Boolean,
            },
            -- Text
            ["Text"] = {
                ["Set"] = function(self, text)
                    self:SetText(text)
                end,
                
                ["Get"] = function(self)
                    return self:GetText()
                end,
                
                ["Type"] = _PropertyType.String,
            },
            -- Container
            ["Container"] = {
                ["Get"] = function(self)
                    return self.__Container.Container
                end,
                
                ["Type"] = _PropertyType.Object,
            },
        }
        
        -- New
        local _New = function(parent)
            local tab = CreateFrame("Button",nil,parent)
            tab.Width = 64
            tab.Height = BUTTON_HEIGHT
            
            tab:SetHighlightTexture("Interface\\PaperDollInfoFrame\\UI-Character-Tab-Highlight")
            local t = tab:GetHighlightTexture()
            t:SetBlendMode("ADD")
            t:SetPoint("TOPLEFT",tab,"TOPLEFT",2,-7)
            t:SetPoint("BOTTOMRIGHT",tab,"BOTTOMRIGHT",-2,-3)
            
            local left = CreateFrame("Texture", "Left", tab, "BACKGROUND")
            local middle = CreateFrame("Texture", "Middle", tab, "BACKGROUND")
            local right = CreateFrame("Texture", "Right", tab, "BACKGROUND")
            local text = CreateFrame("FontString", "Text", tab, "BACKGROUND","GameFontNormalSmall")
                        
            text:SetPoint("LEFT",tab,"LEFT",5,-4)
            text:SetPoint("RIGHT",tab,"RIGHT",-5,-4)
            text:SetHeight(18)
            text:SetText("NewTab")
            
            left:SetTexture("Interface\\ChatFrame\\ChatFrameTab")
            middle:SetTexture("Interface\\ChatFrame\\ChatFrameTab")
            right:SetTexture("Interface\\ChatFrame\\ChatFrameTab")
            
            left:SetWidth(16)
            left:SetHeight(32)
            middle:SetWidth(44)
            middle:SetHeight(32)
            right:SetWidth(16)
            right:SetHeight(32)
            
            left:SetTexCoord(0,0.25,0,1)            
            middle:SetTexCoord(0.25,0.75,0,1)
            right:SetTexCoord(0.75,1,0,1)
            
            left:SetPoint("TOPLEFT",tab,"TOPLEFT",0,0)
            right:SetPoint("TOPRIGHT",tab,"TOPRIGHT",0,0)            
            middle:SetPoint("LEFT",left,"RIGHT",0,0)
            middle:SetPoint("RIGHT",right,"LEFT",0,0)
            
            -- Container
            local container = CreateFrame("ScrollForm", nil, parent.__Root:GetChild("Body"))
                        
            tab.__Container = container
        
            tab.OnClick = OnClick
            
            -- Parent map
            parent.__TabNum = (parent.__TabNum or 0) + 1
            tab.__TabIndex = parent.__TabNum
            
			--- Anchor
			if tab.__TabIndex == 1 then
				tab:SetPoint("TOPLEFT", parent, "TOPLEFT", 0, 0)
			else
				tab:SetPoint("TOPLEFT", parent:GetChild("TabButton"..(tab.__TabIndex-1)), "TOPRIGHT", 0, 0)
			end
			container:SetAllPoints(parent.__Root:GetChild("Body"))
			container:Hide()
            
            return tab
        end
        
        local _WidgetInfo = {
            ["WidgetName"] = _WidgetName,
            ["Base"] = _Base,
            ["FuncProxy"] = _FuncProxy,
            ["Property"] = _Property,
            ["ScriptType"] = _ScriptType,
            ["New"] = _New,
        }
        
        TabButton = _GUI.NewWidget(_WidgetInfo)
    end
    
    ------------------------------------------------------
	--------------------- TabGroup  ----------------------
	------------------------------------------------------    
	local _WidgetName = "TabGroup"
    local _Base = "Frame"
    
    -- Scripts
    local function GetTabButton(self, name)
		local header = self.__HeaderContainer
        if name and header.__TabNum and header.__TabNum > 0 then
            for i = 1,header.__TabNum do
                if header:GetChild("TabButton"..i).Text == name then
                    return header:GetChild("TabButton"..i)
                end
            end
        end
        
        return nil
    end
    
    local function CloseButtOnClick(self)
		local header = self.Parent.__HeaderContainer
        if header.__SelectTab then
            header.__SelectTab:Dispose()
        end
        if header.__TabNum == 0 then
            header.__SelectTab = nil
            self:Hide()
        end
    end
    
	local function UpdateTab(self)
		local header = self:GetChild("Header")
		local tabCon = self.__HeaderContainer
		local width = 0
		
		-- Width
		if tabCon.__TabNum and tabCon.__TabNum > 0 then
			for i = 1, tabCon.__TabNum do
				width = width + tabCon:GetChild("TabButton"..i).Width
			end
			tabCon.Width = width
		else
			tabCon.Width = header.Width
		end
		
		if not tabCon.__TabNum or tabCon.__TabNum <= 0 or tabCon.Width <= header.Width then
			tabCon:SetPoint("TOPLEFT",header,"TOPLEFT",0,0)
			tabCon.__OffSet = 0
			self:GetChild("LeftBtn"):Hide()
			self:GetChild("RightBtn"):Hide()
		else
			self:GetChild("LeftBtn"):Show()
			self:GetChild("RightBtn"):Show()
		end
	end
    
	local function OnSizeChanged(self)
		UpdateTab(self.Parent.__Root)
	end
    
    local function OnSizeChanged2(self)
        UpdateTab(self.Parent)
    end
    	
    local function OnTabSelect(self)
        local parent = self.Parent
        
        if parent.__SelectTab ~= self then
            parent.__SelectTab = self
            parent.__Root:Fire("OnTabChange")
        end
    end
	
	local function OnLeftBtnClk(self)
		local header = self.Parent:GetChild("Header")
		local tabCon = self.Parent.__HeaderContainer
		
		tabCon.__OffSet = (tabCon.__OffSet or 0) - (header.Width/2)
		if tabCon.__OffSet < 0 then
			tabCon.__OffSet = 0
		end
		tabCon:SetPoint("TOPLEFT",header,"TOPLEFT",0-tabCon.__OffSet,0)
	end
	
	local function OnRightBtnClk(self)
		local header = self.Parent:GetChild("Header")
		local tabCon = self.Parent.__HeaderContainer
		
		tabCon.__OffSet = (tabCon.__OffSet or 0) + (header.Width/2)
		if tabCon.__OffSet > (tabCon.Width - header.Width) then
			tabCon.__OffSet = tabCon.Width - header.Width
		end
		tabCon:SetPoint("TOPLEFT",header,"TOPLEFT",0-tabCon.__OffSet,0)
	end
	
	-- ScriptType
	local _ScriptType = {
        ["OnTabChange"] = true,
	}
    	
	-- FuncProxy
	local _FuncProxy = {
        -- Dispose, release resource
        ["Dispose"] = function(self)			
			local header = self.__HeaderContainer
            
            if header.__TabNum and header.__TabNum > 0 then
                for i = header.__TabNum, 1, -1 do
                    header:GetChild("TabButton"..i):Dispose()
                end
            end

            -- Call super's dispose
			self:CallMethod(_Widget[_Base], "Dispose")
        end,
        ["AddTab"] = function(self, name)		
            if not name or type(name) ~= "string" then
                error("The parameter must be a string.")
            end
            
            local tab = GetTabButton(self, name)
            
            if tab then
                return tab
            end
            
            tab = CreateFrame(TabButton, nil, self.__HeaderContainer)
            tab.Text = name
            
			tab.OnSizeChanged = OnSizeChanged
            tab.OnTabSelect = OnTabSelect
            
            -- If first use, select the first tab.
            if tab.__TabIndex == 1 then
                tab:Select()
                if not self.__HideCloseBtn then
                    self:GetChild("CloseBtn"):Show()
                end
            end
			
			UpdateTab(self)
 
            return tab
        end,
        ["RemoveTab"] = function(self, name)
            local tab = GetTabButton(self, name)
            if tab then
                tab:Dispose()
            end
            
            UpdateTab(self)
        end,
		["RemoveTabByIndex"] = function(self, id)
			local header = self.__HeaderContainer
			if header.__TabNum and header.__TabNum >= id then
				header:GetChild("TabButton"..id):Dispose()			
				UpdateTab(self)
			end
		end,
        ["SelectTab"] = function(self, name)
            local tab = GetTabButton(self, name)
            if tab then
                tab:Select()
            end
        end,
        ["GetTab"] = function(self, name)
            return GetTabButton(self, name)
        end,
		["GetTabByIndex"] = function(self, id)
			local header = self.__HeaderContainer
			if header.__TabNum and header.__TabNum >= id then
				return header:GetChild("TabButton"..id)
			end
			
			return nil
		end,
        ["GetSelectTab"] = function(self)
            return self.__HeaderContainer.__SelectTab
        end,
        --[[["SetAlignment"] = function(self, align)
			local header = self:GetChild("Header")
			local tabCon = self.__HeaderContainer
			local body = self:GetChild("Body")
			local closeBtn = self:GetChild("CloseBtn")
			local leftBtn = self:GetChild("LeftBtn")
			local rightBtn = self:GetChild("RightBtn")
			local selTab, left, middle, right
			
            if align == TABALIGN_TOP or align == TABALIGN_BOTTOM then
                if align ~= self.__Alignment then
                    self.__Alignment = align
					
					if self.__Alignment == TABALIGN_BOTTOM then
						body:ClearAllPoints()
						header:ClearAllPoints()
				        leftBtn:ClearAllPoints()
				        rightBtn:ClearAllPoints()
						closeBtn:ClearAllPoints()
						closeBtn:SetPoint("BOTTOMRIGHT",self,"BOTTOMRIGHT")
				        rightBtn:SetPoint("BOTTOM", self, "BOTTOM")
				        rightBtn:SetPoint("RIGHT", closeBtn, "LEFT")
				        leftBtn:SetPoint("BOTTOM", self, "BOTTOM")
				        leftBtn:SetPoint("RIGHT", rightBtn, "LEFT")
				        header:SetPoint("BOTTOMLEFT", self, "BOTTOMLEFT")
						header:SetPoint("RIGHT", leftBtn, "LEFT")
						body:SetPoint("LEFT", self, "LEFT")
						body:SetPoint("RIGHT", self, "RIGHT")
						body:SetPoint("BOTTOM", header, "TOP")
						body:SetPoint("TOP", self, "TOP")
						
                        if tabCon.__TabNum and tabCon.__TabNum > 0 then
                            for i = 1,tabCon.__TabNum do
                                selTab = tabCon:GetChild("TabButton"..i)
                                
                                left = selTab:GetChild("Left")
                                middle = selTab:GetChild("Middle")
                                right = selTab:GetChild("Right")
                                
                                left:SetTexCoord(0,0.25,0,1)
                                middle:SetTexCoord(0.25,0.75,0,1)
                                right:SetTexCoord(0.75,1,0,1)
                            end
                        end
					else
						body:ClearAllPoints()
						header:ClearAllPoints()
				        leftBtn:ClearAllPoints()
				        rightBtn:ClearAllPoints()
						closeBtn:ClearAllPoints()
						closeBtn:SetPoint("TOPRIGHT",self,"TOPRIGHT")
				        rightBtn:SetPoint("TOP", self, "TOP")
				        rightBtn:SetPoint("RIGHT", closeBtn, "LEFT")
				        leftBtn:SetPoint("TOP", self, "TOP")
				        leftBtn:SetPoint("RIGHT", rightBtn, "LEFT")
				        header:SetPoint("TOPLEFT", self, "TOPLEFT")
						header:SetPoint("RIGHT", leftBtn, "LEFT")
						body:SetPoint("LEFT", self, "LEFT")
						body:SetPoint("RIGHT", self, "RIGHT")
						body:SetPoint("BOTTOM", self, "BOTTOM")
						body:SetPoint("TOP", header, "BOTTOM")
						
                        if tabCon.__TabNum and tabCon.__TabNum > 0 then
                            for i = 1,tabCon.__TabNum do
                                selTab = tabCon:GetChild("TabButton"..i)
                                
                                left = selTab:GetChild("Left")
                                middle = selTab:GetChild("Middle")
                                right = selTab:GetChild("Right")
                                
                                left:SetTexCoord(0,0.25,0,1)
                                middle:SetTexCoord(0.25,0.75,0,1)
                                right:SetTexCoord(0.75,1,0,1)
                            end
                        end
					end
                end
            end
        end,
        ["GetAlignment"] = function(self)
            return self.__Alignment or TABALIGN_TOP
        end,--]]
        ["ShowCloseBtn"] = function(self)
            self.__HideCloseBtn = false
            if self.__HeaderContainer.__TabNum > 0 then
                self:GetChild("CloseBtn"):Show()
            end
        end,
        ["HideCloseBtn"] = function(self)
            self.__HideCloseBtn = true
            self:GetChild("CloseBtn"):Hide()
        end,
    }
    
	-- Property
	local _Property = {
        --[[["Alignment"] = {
            ["Set"] = function(self, align)
                self:SetAlignment(align)
            end,
            
            ["Get"] = function(self)
                return self:GetAlignment()
            end,
            
            ["Type"] = _PropertyType.TabAlignment,
        },--]]
        ["UseCloseBtn"] = {            
            ["Set"] = function(self, flag)
                if flag then
                    self:ShowCloseBtn()
                else
                    self:HideCloseBtn()
                end
            end,
            
            ["Get"] = function(self)
                return (not self.__HideCloseBtn and true) or false
            end,
            
            ["Type"] = _PropertyType.Boolean,
        },
		["TabNum"] = {
			["Get"] = function(self)
				return self.__HeaderContainer.__TabNum or 0
			end,
			
			["Type"] = _PropertyType.Number
		},
	}
	
    -- New
    local _New = function(parent)    
		local frame = CreateFrame("Frame",nil,parent)
        --frame.__Alignment = TABALIGN_TOP
        
		local closeButton = CreateFrame("Button","CloseBtn",frame)
		closeButton:SetPoint("TOPRIGHT",frame,"TOPRIGHT")
        closeButton:Hide()
        closeButton.Style = "CLOSE"
		closeButton.OnClick = CloseButtOnClick
        
        local btnScrollRight = CreateFrame("Button", "RightBtn", frame)
        btnScrollRight:SetWidth(32)
        btnScrollRight:SetHeight(32)
        btnScrollRight:ClearAllPoints()
        btnScrollRight:SetPoint("TOP", frame, "TOP", 0, 0)
        btnScrollRight:SetPoint("RIGHT", closeButton, "LEFT", 0, 0)
        btnScrollRight:SetNormalTexture("Interface\\BUTTONS\\UI-SpellbookIcon-NextPage-Up.blp")
        btnScrollRight:SetPushedTexture("Interface\\BUTTONS\\UI-SpellbookIcon-NextPage-Down.blp")
        btnScrollRight:SetDisabledTexture("Interface\\BUTTONS\\UI-SpellbookIcon-NextPage-Disabled.blp")
        btnScrollRight:SetHighlightTexture("Interface\\Buttons\\UI-Common-MouseHilight.blp", "ADD")
        btnScrollRight:Hide()
		btnScrollRight.OnClick = OnRightBtnClk
        
        local btnScrollLeft = CreateFrame("Button", "LeftBtn", frame)
        btnScrollLeft:SetWidth(32)
        btnScrollLeft:SetHeight(32)
        btnScrollLeft:ClearAllPoints()
        btnScrollLeft:SetPoint("TOP", frame, "TOP", 0, 0)
        btnScrollLeft:SetPoint("RIGHT", btnScrollRight, "LEFT", 0, 0)        
        btnScrollLeft:SetNormalTexture("Interface\\BUTTONS\\UI-SpellbookIcon-PrevPage-Up.blp")
        btnScrollLeft:SetPushedTexture("Interface\\BUTTONS\\UI-SpellbookIcon-PrevPage-Down.blp")
        btnScrollLeft:SetDisabledTexture("Interface\\BUTTONS\\UI-SpellbookIcon-PrevPage-Disabled.blp")
        btnScrollLeft:SetHighlightTexture("Interface\\Buttons\\UI-Common-MouseHilight.blp", "ADD")
        btnScrollLeft:Hide()
		btnScrollLeft.OnClick = OnLeftBtnClk
        
        local header = CreateFrame("ScrollFrame","Header",frame)
        header:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, 0)
		header:SetPoint("RIGHT", btnScrollLeft, "LEFT", 0, 0)
        header.Height = BUTTON_HEIGHT
		header.MouseEnabled = true
        header.OnSizeChanged = OnSizeChanged2
        
        local headerContainer = CreateFrame("Frame", "Container", header)
        header:SetScrollChild(headerContainer)
		headerContainer:SetPoint("TOPLEFT",header,"TOPLEFT",0,0)
        headerContainer.Height = header.Height
        headerContainer.Width = header.Width
        headerContainer.__TabNum = 0
		
		local body = CreateFrame("Frame", "Body", frame)
		body:SetPoint("LEFT", frame, "LEFT", 0,0)
		body:SetPoint("RIGHT", frame, "RIGHT", 0,0)
		body:SetPoint("BOTTOM", frame, "BOTTOM", 0,0)
		body:SetPoint("TOP", header, "BOTTOM", 0,0)
        
        frame.__HeaderContainer = headerContainer
        headerContainer.__Root = frame
        
        return frame
    end
	
    local _WidgetInfo = {
        ["WidgetName"] = _WidgetName,
        ["Base"] = _Base,
        ["FuncProxy"] = _FuncProxy,
        ["Property"] = _Property,
        ["ScriptType"] = _ScriptType,
        ["New"] = _New,
    }
    
    _Widget[_WidgetName] = _GUI.NewWidget(_WidgetInfo)    
end